﻿using AntiVmDetection.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.ServiceProcess;
using AntiVmDetection.Utils;
using System.IO;

namespace AntiVmDetection.Impl
{
    class VmwareCheat : ICheat
    {
        static readonly string BIOSKey = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS";
        static readonly Dictionary<string, dynamic> biosKeyMap = new Dictionary<string, dynamic>()
        {
            {"BaseBoardManufacturer", "LENOVO"},
            {"BaseBoardProduct", "LNVNB161216"},
            {"BaseBoardVersion", "SDK0T76479WIN"},
            {"BIOSVendor", "LENOVO"},
            {"BIOSVersion", "H2CN26WW"},
            {"BiosMajorRelease", 0x01},
            {"BiosMinorRelease", 0x1a},
            {"ECFirmwareMajorRelease", 0x01},
            {"ECFirmwareMinorRelease", 0x1a},
            {"SystemFamily", "XiaoXinAir 15ALC 2021"},
            {"SystemManufacturer", "LENOVO"},
            {"SystemProductName", "82LN"},
            {"SystemSKU", "LENOVO_MT_82LN_BU_idea_FM_XiaoXinAir 15ALC 2021"},
            {"SystemVersion", "Lenovo XiaoXinAir 15ALC 2021"},
        };
        static readonly string ServiceKey = @"SYSTEM\CurrentControlSet\Services\";
        static readonly Dictionary<string, string> servicesMap = new Dictionary<string, string>()
        {
            { "VGAuthService","Cheat1"},
            { "vmvss",        "Cheat2"},
            { "VMTools",      "Cheat3"},
            //{ "vm3dservice",  "Cheat4"},
        };
        static readonly Dictionary<string, string> servicePathConfig = new Dictionary<string, string>()
        {
            {@"C:\Program Files\VMware\VMware Tools\VMware VGAuth\VGAuthService.exe", @"C:\Program Files\VMware\VMware Tools\VMware VGAuth\Cheat1.exe"},
            {"", ""},
            {@"C:\Program Files\VMware\VMware Tools\vmtoolsd.exe", @"C:\Program Files\VMware\VMware Tools\Cheat3.exe"},
            //{@"C:\windows\system32\vm3dservice.exe", @"C:\windows\system32\Cheat4.exe"},
        };
        public bool CheatBIOS()
        {
            foreach (var item in biosKeyMap)
            {
                Registry.SetValue(BIOSKey, item.Key, item.Value);
            }
            return true;
        }
        public bool CheatService()
        {
            UInt32 regKey;
            Winapi.RegOpenKey(Winapi.HKEY_LOCAL_MACHINE, ServiceKey, out regKey);
            RegistryKey key = Registry.LocalMachine.OpenSubKey(ServiceKey);
            var enumerator = servicePathConfig.GetEnumerator();
            foreach (var pair in servicesMap)
            {
                enumerator.MoveNext();
                Winapi.RegRenameKey(regKey, pair.Key, pair.Value);
                if (enumerator.Current.Key.Length == 0)
                    continue;

                RegistryKey serviceKey = key.OpenSubKey(pair.Value, true);
                if (serviceKey == null)
                    continue;
                
                serviceKey.SetValue("ImagePath", $"\"{enumerator.Current.Value}\"");
                File.Move(enumerator.Current.Key, enumerator.Current.Value);
            }
            Winapi.RegCloseKey(regKey);
            return true;
        }
        public bool RecoverService()
        {
            UInt32 regKey;
            Winapi.RegOpenKey(Winapi.HKEY_LOCAL_MACHINE, ServiceKey, out regKey);
            RegistryKey key = Registry.LocalMachine.OpenSubKey(ServiceKey);
            var enumerator = servicePathConfig.GetEnumerator();
            foreach (var pair in servicesMap)
            {
                enumerator.MoveNext();
                Winapi.RegRenameKey(regKey, pair.Value, pair.Key); 
                if (enumerator.Current.Key.Length == 0)
                    continue;

                RegistryKey serviceKey = key.OpenSubKey(pair.Key, true);
                if (serviceKey == null)
                    continue;

                serviceKey.SetValue("ImagePath", $"\"{enumerator.Current.Key}\"");
                try
                {
                    File.Move(enumerator.Current.Value, enumerator.Current.Key);
                }catch(FileNotFoundException){}
            }
            Winapi.RegCloseKey(regKey);
            return true;
        }
        public bool CheatDetection()
        {
            CheatBIOS();
            CheatService();
            return true;
        }

        public bool Recover()
        {
            RecoverService();
            return true;
        }
    }
}
